/*
 * Saphre - Suffix Arrays for Phrase Extraction
 * Copyright (C) 2013 
 * Dale Gerdemann - Tübingen, Germany 
 * Niko Schenk - Frankfurt am Main, Germany
 * All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package util;

/**
 * This class is a wrapper to make a sequence of int look like a String. 
 * The purpose is to make it easy to use string algorithms with int[]. 
 * This class could use a few more methods, but at least it's a start.
 * 
 * @author Dale Gerdemann
 * 
 */
import java.util.*;

public final class IntString implements Comparable<IntString> {

    public static IntString EMPTY;

    static {
        int[] v = new int[0];
        EMPTY = new IntString(v);
    }
    int[] value;  // characters
    int offset;   // index of first char into array
    int count;    // length of string
    int hash;     // cache of hashCode()

    public IntString(int[] value) {
        this.value = value;
        this.offset = 0;
        this.count = value.length;
    }

    public IntString(int offset, int count, int[] value) {
        this.offset = offset;
        this.count = count;
        this.value = value;
    }

    public int charAt(int i) {
        return value[offset + i];
    }

    public int at(int i) {
        return value[offset + i];
    }

    public int length() {
        return count;
    }

    public IntString plus(int c) {
        // dubious optimization #1
        if (offset + count < value.length
                && c == value[offset + count]) {
            return new IntString(offset, count + 1, value);
        }
        int[] value1 = new int[count + 1];
        value1[count] = c;
        for (int i = offset, k = 0; i < count; i++, k++) {
            value1[k] = value[i];
        }
        // dubious optimization #2
        value = value1;
        return new IntString(0, count + 1, value1);
    }

    public IntString plus(IntString s) {
        int count1 = count + s.length();
        int[] value1 = new int[count1];
        for (int i = count, j = 0; i < count1; i++, j++) {
            value1[i] = s.charAt(j);
        }
        for (int i = offset, k = 0; i < count; i++, k++) {
            value1[k] = value[i];
        }
        return new IntString(0, count1, value1);
    }

    @Override
    public int compareTo(IntString other) {
        return compareTo(value, offset, count,
                other.value, other.offset, other.count);
    }

    private int compareTo(int[] v, int o, int c,
            int[] v1, int o1, int c1) {
        if (c == 0) {
            if (c1 == 0) {
                return 0;
            } else {
                return -1;
            }
        } else if (c1 == 0) {
            return 1;
        }
        if (v[o] < v1[o1]) {
            return -1;
        } else if (v1[o1] < v[o]) {
            return 1;
        }
        return compareTo(v, o + 1, c - 1, v1, o1 + 1, c1 - 1);
    }

    public IntString substring(int from, int to) {
        return new IntString(offset + from, to - from, value);
    }

    // return offset of first match or N if no match
    public int search(IntString pat) {
        int M = pat.length();
        int N = length();
        int i, j;
        for (i = 0, j = 0; i < N && j < M; i++) {
            if (pat.at(i) == at(j)) {
                j++;
            } else {
                i -= j;
                j = 0;
            }
        }
        if (j == M) {
            return i - M;    // found
        } else {
            return N;        // not found
        }
    }

    @Override
    public String toString() {
        return Arrays.toString(Arrays.copyOfRange(value,
                offset,
                offset + count));
    }

    public int[] toArray() {
        return Arrays.copyOfRange(value, offset, offset + count);
    }

    public static int[] toArray(List<Integer> list) {
        int[] result = new int[list.size()];
        for (int i = 0; i < list.size(); i++) {
            result[i] = list.get(i);
        }
        return result;
    }

    public static int[] toArray1(List<Integer> list) {
        int[] result = new int[list.size() + 1];
        for (int i = 1; i <= list.size(); i++) {
            result[i] = list.get(i - 1);
        }
        return result;
    }
}
